package se.webbzon.boltzmann.minigame.machine;

import se.webbzon.boltzmann.minigame.sandbox.DefaultSandBoxItem;
import se.webbzon.boltzmann.minigame.sandbox.SandBox;
import se.webbzon.boltzmann.minigame.sandbox.SandBoxIcon;
import se.webbzon.boltzmann.minigame.sandbox.SandBoxItem;
import se.webbzon.boltzmann.minigame.sandbox.SandBoxObject;
import se.webbzon.boltzmann.minigame.sandbox.SandBoxSpawner;
import se.webbzon.boltzmann.resource.Resources;
import se.webbzon.oschi01.resourceset.ResourceSet;
import se.webbzon.oschi01.textureset.Texture3D;
import se.webbzon.oschi01.utilities.Direction;
import se.webbzon.oschi01.worldarea.WorldArea;
import se.webbzon.oschi01.worldcamera.WorldCameraPane;
import se.webbzon.oschi01.worldobject.WorldObject;

public abstract class SandBoxPipe<T extends SandBoxItem> extends DefaultSandBoxItem implements SandBoxSpawner<T> {
	
	// The 2-dimensional depth of this sand box item
	private static final int depth2d = 1;
	
	// The size of the pipe
	private static final int width = 32, height = 32;
	
	// The duration of the oscillation (in steps)
	private static final int duration = 30;
	
	// The texture set of this pipe
	private final ResourceSet<Texture3D> textureSet;
	
	// The direction of the pipe
	private final Direction dir;
	
	// The remaining time (in steps) until the oscillation stops
	private int remaining;
	
	// The size of the pipe
	private double size;
	
	/*============================================================
	Constructors
	============================================================*/
	
	public SandBoxPipe(Direction dir) {
		this.dir = dir;
		textureSet = Resources.getTextureSet("machine_pipe_01");
		remaining = 0;
		size = 1;
		setInstance(new Instance());
		setSize(width,height);
	}
	
	/*============================================================
	Public Methods
	============================================================*/
	
	public final T spawn() {
		T t = createSandBoxItem();
		switch (dir) {
		case LEFT: t.setPosition(getX() + getWidth()/2, getY()); break;
		case UP: t.setPosition(getX(), getY() - getHeight()/2); break;
		case RIGHT: t.setPosition(getX() - getWidth()/2, getY()); break;
		case DOWN: t.setPosition(getX(), getY() + getHeight()/2); break;
		}
		remaining = duration;
		return t;
	}
	
	/*============================================================
	Protected Methods
	============================================================*/
	
	/** Creates a new sand box item. **/
	protected abstract T createSandBoxItem();
	
	/*============================================================
	Private Classes
	============================================================*/
	
	private final class Instance extends SandBoxObject {

		public Instance() {
			super(WorldObject.onPostDraw + WorldObject.onStep, depth2d);
		}

		@Override public void onAttach(final SandBox box) {};

		@Override public void onDetach(SandBox box) {}
		
		@Override public void onStep(WorldArea world) {
			if (remaining > 0) {
				double t = remaining--;
				size = 1 - 0.3 * Math.sin(Math.exp(t*0.07) - 1);
			} else if (remaining == 0)
				size = 1;
		}

		@Override public void onPostDraw(WorldArea world, WorldCameraPane hud) {
			final int w, h;
			if (dir == Direction.LEFT || dir == Direction.RIGHT) {
				w = width;
				h = (int) (size * height);
			} else {
				w = (int) (size * width);
				h = height;
			}
			int x = (int) getX()-w/2, y = (int) getY()-h/2;
			hud.drawTexture(textureSet.get(dir.ordinal()), x, y, w, h);
		}

		@Override public SandBoxIcon createIcon() {
			return null;
		}
		
	}

}
